package n9_设计模式_生产者_消费者;

import lombok.extern.slf4j.Slf4j;

import java.util.LinkedList;

import static utils.Sleeper.sleep;

/**
 * 设计模式---生产者和消费者
 *
 * @author fu
 * @date 2021-12-25 17:11
 * 概要：
 * XXXXX
 */
@Slf4j(topic = "c.T1")
public class T1_ProducterConsumer {

    public static void main(String[] args) {
        // 1. 初始化 消息队列 容器大小
        final MessageQueue queue = new MessageQueue(2);
        log.debug("--------------------------------------------");

        new Thread(()->{

            while(true){
                sleep(3);
                queue.take();
            }

        },"消费者-").start();

        // 2. [生产者] 线程
        for (int i = 0; i < 3; i++) {
            sleep(1);
            int id = i;// lambda表达式变量必须是final的 i一直变会报错！ [id 在每次循环都会产生新的id，所以解决]
            new Thread(()->{

                queue.put(new Message(id, "msg"+id));

            },"生产者"+id).start();
        }


        // 3. [消费者] 线程
        new Thread(()->{

            while(true){
                sleep(3);
                queue.take();
            }

        },"消费者-").start();
    }

}


/*-----------------------------------------------------------------------
|                                                                       |
|   消息队列类， 【java 线程之间通信,(注意：不同于RabbitMQ进程间通信！)】      |
|                                                                      |
|======================================================================*/
@Slf4j(topic = "c.Me")
class MessageQueue{

    // 消息[容器]    LinkedList的频繁掺入、删除效率高
    private final LinkedList<Message> list = new LinkedList<>();
    // 消息[容量]
    private int capacity;

    public MessageQueue(int capacity) {
        this.capacity = capacity;
    }

    // get
    public Message take(){

        synchronized (list){
            while(list.isEmpty()){
                try {
                    log.debug("KKKKKKKK 空值等待take KKKKKKKK");
                    list.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            // 从队列头部获取消息
            final Message message = list.removeFirst();
            list.notifyAll();
            log.debug("<<<<< 获取了一个消息--- {}",message.toString());
            return message;
        }

    }

    // put
    public void put(Message message){

        synchronized (list){
//            while(list.size()>=this.capacity){
            while(list.size()==this.capacity){
                try {
                    log.debug("MMMMMMMMM put满值等待 MMMMMMMMM");
                    list.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            log.debug("put---successful---{}",message.getId());
            list.addLast(message);
            list.notifyAll();
        }
    }

}
/*-------------------------------------------------------------------------------------------
|                                                                                           |
|  消息类 【1. 必须有 ID属性 2. [-final 对象不可变-]所以只在new对象时存入属性 没有set方法】         |
|                                                                                          |
|===========================================================================================*/
final class Message{
    private int id;
    private Object value;

    public Message(int id, Object value) {
        this.id = id;
        this.value = value;
    }

    public int getId() {
        return id;
    }

    public Object getValue() {
        return value;
    }

    @Override
    public String toString() {
        return "Message{" +
                "id=" + id +
                ", value=" + value +
                '}';
    }
}





